package com.knife.scheduler.infra.job;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.knife.common.exception.CommonException;
import com.knife.common.utils.KnifeSpringUtil;
import com.knife.scheduler.domain.entity.KnifeJobHistory;
import com.knife.scheduler.domain.entity.KnifeJobInfo;
import com.knife.scheduler.infra.KnifeJobMarker;
import com.knife.scheduler.infra.constants.KnifeSchedulerConstant;
import com.knife.scheduler.infra.mapper.KnifeJobHistoryMapper;
import com.knife.scheduler.infra.mapper.KnifeJobInfoMapper;
import com.knife.scheduler.infra.registry.KnifeJobRegistry;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.util.ObjectUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * quartz定时任务 与 knife定时任务 的桥梁
 * <p>
 * knife扫描自己的注解和接口找到想要定时执行的任务内容，通过本类委托给quartz的任务
 *
 * @author： 76875
 * @date： 2022/4/2 星期六 10:11
 * @description：
 * @modifiedBy：
 * @version: 1.0
 */
//持久化
@PersistJobDataAfterExecution
//禁止并发执行(Quartz不要并发地执行同一个job定义（这里指一个job类的多个实例）)
@DisallowConcurrentExecution
@Slf4j
public class KnifeJobDetail implements Job, KnifeSchedulerConstant {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 创建quartz定时任务
        JobDataMap jobDataMap = getJobDataMap(jobExecutionContext);
        String code = jobDataMap.getString(CODE);
        KnifeJobMarker jobHandler = KnifeJobRegistry.getJobHandler(code);
        // 在开发环境下，通常会出现开发人员代码不一致的情况，所以需要避免调度任务执行到未注册服务上
        // 未找到注册任务，则跳过不执行
        if (ObjectUtils.isEmpty(jobHandler)) {
            log.debug("本机未开启定时任务配置{},将不执行任务", "executorFlag");
            return;
        }
        // 获取数据
        KnifeJobInfoMapper knifeJobInfoMapper = KnifeSpringUtil.getBean(KnifeJobInfoMapper.class);
        ObjectMapper objectMapper = KnifeSpringUtil.getBean(ObjectMapper.class);
        LambdaQueryWrapper<KnifeJobInfo> knifeJobInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        knifeJobInfoLambdaQueryWrapper.eq(KnifeJobInfo::getJobCode, code);
        KnifeJobInfo value = knifeJobInfoMapper.selectOne(knifeJobInfoLambdaQueryWrapper);
        if (ObjectUtils.isEmpty(value)) {
            return;
        }
        KnifeJobHistory knifeJobHistory = new KnifeJobHistory();
        // 记录调度任务执行日志
        initJobHistory(knifeJobHistory, value);
        try {
            Map<String, String> map = StringUtils.isNotBlank(value.getJobParam()) ? objectMapper.readValue(value.getJobParam(), new TypeReference<Map<String, String>>() {
            }) : new HashMap<>(16);
            jobHandler.beforeSchedulerTask(map);
            jobHandler.schedulerTask(map);
            knifeJobHistory.setExecuteStatus("success");
            jobHandler.afterSchedulerTask(map);
        } catch (Exception e) {
            knifeJobHistory.setExecuteStatus("fail");
            knifeJobHistory.setErrorMsg(e.getMessage());
            throw new CommonException("任务异常:"+e.getMessage());
        } finally {
            KnifeJobHistoryMapper historyMapper = KnifeSpringUtil.getBean(KnifeJobHistoryMapper.class);
            historyMapper.insert(knifeJobHistory);
        }
    }

    private JobDataMap getJobDataMap(JobExecutionContext jobExecutionContext) {
        return jobExecutionContext.getJobDetail().getJobDataMap();
    }

    private void initJobHistory(KnifeJobHistory knifeJobHistory, KnifeJobInfo knifeJobInfo) {
        knifeJobHistory.setExecuteDate(new Date());
        knifeJobHistory.setJobId(knifeJobInfo.getId());
        knifeJobHistory.setTenantId(knifeJobInfo.getTenantId());
    }

}
